// CmdWnd.h : Declaration of the CCmdWnd
#pragma once
#include "resource.h"       // main symbols
#include <atlctl.h>
#include "CmdWindow.h"
#include "_ICmdWndEvents_CP.h"
#include "CmdInstanceThread.h"
#include "PipeReadThread.h"

#if defined(_WIN32_WCE) && !defined(_CE_DCOM) && !defined(_CE_ALLOW_SINGLE_THREADED_OBJECTS_IN_MTA)
#error "Single-threaded COM objects are not properly supported on Windows CE platform, such as the Windows Mobile platforms that do not include full DCOM support. Define _CE_ALLOW_SINGLE_THREADED_OBJECTS_IN_MTA to force ATL to support creating single-thread COM object's and allow use of it's single-threaded COM object implementations. The threading model in your rgs file was set to 'Free' as that is the only threading model supported in non DCOM Windows CE platforms."
#endif


// CCmdWnd
class ATL_NO_VTABLE CCmdWnd :
	public CComObjectRootEx<CComSingleThreadModel>,
	public IDispatchImpl<ICmdWnd, &IID_ICmdWnd, &LIBID_CmdWindowLib, /*wMajor =*/ 1, /*wMinor =*/ 0>,
	public IPersistStreamInitImpl<CCmdWnd>,
	public IOleControlImpl<CCmdWnd>,
	public IOleObjectImpl<CCmdWnd>,
	public IOleInPlaceActiveObjectImpl<CCmdWnd>,
	public IViewObjectExImpl<CCmdWnd>,
	public IOleInPlaceObjectWindowlessImpl<CCmdWnd>,
	public ISupportErrorInfo,
	public IConnectionPointContainerImpl<CCmdWnd>,
	public CProxy_ICmdWndEvents<CCmdWnd>,
	public IPersistStorageImpl<CCmdWnd>,
	public ISpecifyPropertyPagesImpl<CCmdWnd>,
	public IQuickActivateImpl<CCmdWnd>,
#ifndef _WIN32_WCE
	public IDataObjectImpl<CCmdWnd>,
#endif
	public IProvideClassInfo2Impl<&CLSID_CmdWnd, &__uuidof(_ICmdWndEvents), &LIBID_CmdWindowLib>,
#ifdef _WIN32_WCE // IObjectSafety is required on Windows CE for the control to be loaded correctly
	public IObjectSafetyImpl<CCmdWnd, INTERFACESAFE_FOR_UNTRUSTED_CALLER>,
#endif
	public CComCoClass<CCmdWnd, &CLSID_CmdWnd>,
	public CComControl<CCmdWnd>,
	public CCmdInstanceThreadListener,
	public CPipeReadThreadListener
{
public:
	static const unsigned int MAX_WAITING_TIME	= (10000);

	static const DWORD FLAG_INITIALIZED		= 0x00000001;
	static const DWORD FLAG_CIT_RUNNING		= 0x00000002;
	static const DWORD FLAG_PRT_RUNNING		= 0x00000004;

public:
	CCmdWnd();
	~CCmdWnd();

DECLARE_OLEMISC_STATUS(	OLEMISC_RECOMPOSEONRESIZE |
						OLEMISC_CANTLINKINSIDE |
						OLEMISC_INSIDEOUT |
						OLEMISC_ACTIVATEWHENVISIBLE |
						OLEMISC_SETCLIENTSITEFIRST)

DECLARE_REGISTRY_RESOURCEID(IDR_CMDWND)


BEGIN_COM_MAP(CCmdWnd)
	COM_INTERFACE_ENTRY(ICmdWnd)
	COM_INTERFACE_ENTRY(IDispatch)
	COM_INTERFACE_ENTRY(IViewObjectEx)
	COM_INTERFACE_ENTRY(IViewObject2)
	COM_INTERFACE_ENTRY(IViewObject)
	COM_INTERFACE_ENTRY(IOleInPlaceObjectWindowless)
	COM_INTERFACE_ENTRY(IOleInPlaceObject)
	COM_INTERFACE_ENTRY2(IOleWindow, IOleInPlaceObjectWindowless)
	COM_INTERFACE_ENTRY(IOleInPlaceActiveObject)
	COM_INTERFACE_ENTRY(IOleControl)
	COM_INTERFACE_ENTRY(IOleObject)
	COM_INTERFACE_ENTRY(IPersistStreamInit)
	COM_INTERFACE_ENTRY2(IPersist, IPersistStreamInit)
	COM_INTERFACE_ENTRY(ISupportErrorInfo)
	COM_INTERFACE_ENTRY(IConnectionPointContainer)
	COM_INTERFACE_ENTRY(ISpecifyPropertyPages)
	COM_INTERFACE_ENTRY(IQuickActivate)
	COM_INTERFACE_ENTRY(IPersistStorage)
#ifndef _WIN32_WCE
	COM_INTERFACE_ENTRY(IDataObject)
#endif
	COM_INTERFACE_ENTRY(IProvideClassInfo)
	COM_INTERFACE_ENTRY(IProvideClassInfo2)
#ifdef _WIN32_WCE // IObjectSafety is required on Windows CE for the control to be loaded correctly
	COM_INTERFACE_ENTRY_IID(IID_IObjectSafety, IObjectSafety)
#endif
END_COM_MAP()

BEGIN_PROP_MAP(CCmdWnd)
	PROP_DATA_ENTRY("_cx", m_sizeExtent.cx, VT_UI4)
	PROP_DATA_ENTRY("_cy", m_sizeExtent.cy, VT_UI4)
	// Example entries
	// PROP_ENTRY("Property Description", dispid, clsid)
	// PROP_PAGE(CLSID_StockColorPage)
END_PROP_MAP()

BEGIN_CONNECTION_POINT_MAP(CCmdWnd)
	CONNECTION_POINT_ENTRY(__uuidof(_ICmdWndEvents))
END_CONNECTION_POINT_MAP()

BEGIN_MSG_MAP(CCmdWnd)
	CHAIN_MSG_MAP(CComControl<CCmdWnd>)
	DEFAULT_REFLECTION_HANDLER()
END_MSG_MAP()
// Handler prototypes:
//  LRESULT MessageHandler(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);
//  LRESULT CommandHandler(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled);
//  LRESULT NotifyHandler(int idCtrl, LPNMHDR pnmh, BOOL& bHandled);

// ISupportsErrorInfo
	STDMETHOD(InterfaceSupportsErrorInfo)(REFIID riid)
	{
		static const IID* arr[] =
		{
			&IID_ICmdWnd,
		};

		for (int i=0; i<sizeof(arr)/sizeof(arr[0]); i++)
		{
			if (InlineIsEqualGUID(*arr[i], riid))
				return S_OK;
		}
		return S_FALSE;
	}

// IViewObjectEx
	DECLARE_VIEW_STATUS(VIEWSTATUS_SOLIDBKGND | VIEWSTATUS_OPAQUE)

// ICmdWnd
public:
	HRESULT OnDraw(ATL_DRAWINFO& di);
	DECLARE_PROTECT_FINAL_CONSTRUCT()
	HRESULT FinalConstruct()	{ return S_OK; }
	void FinalRelease()	{	}

protected:
	CRITICAL_SECTION m_CS;
	DWORD m_dwModuleStatus;

	HWND m_hOutputWindow;

	// Child input pipe
	HANDLE m_hChildStdInPipeRead;
	HANDLE m_hChildStdInPipeWriteDuplicate;

	// Child output pipe
	HANDLE m_hChildStdOutPipeWrite;
	HANDLE m_hChildStdOutPipeReadDuplicate;

	// Child error pipe
	HANDLE m_hChildStdErrorPipeWrite;
	HANDLE m_hChildStdErrorPipeReadDuplicate;

	// Thread parameter resources
	CCmdInstanceThread::LP_PARAMETER	m_pCITParam;
	CPipeReadThread::LP_PARAMETER		m_pPRParam;

public:
	// Implementation of virtual functions
	void CmdInstanceStart();
	void CmdInstanceLog(std::wstring wsLog);
	void CmdInstanceStop();

	void PipeReadThreadStart();
	void PipeReadThreadReceive(const void * pBuffer, const unsigned long nBufLen);
	void PipeReadThreadLog(std::wstring wsLog);
	void PipeReadThreadStop();

protected:
	// Initialize child input output and error output pipe
	HRESULT InitPipe(void);
	// Uninitialize child input output and error output pipe
	HRESULT UnInitPipe(void);
	// Send data to output window
	void SendToOutputWindow(const void * pBuffer, const unsigned long nBufLen);

public:
	STDMETHOD(Init)(BSTR bstrWorkingFolder);
	STDMETHOD(UnInit)(void);
	STDMETHOD(ShowOutputWindow)(VARIANT_BOOL bShow);
	STDMETHOD(Start)(BSTR bstrDirectory, BSTR bstrCommand, VARIANT_BOOL bKeep, VARIANT_BOOL bShow);
	STDMETHOD(Terminate)(void);
};

OBJECT_ENTRY_AUTO(__uuidof(CmdWnd), CCmdWnd)
